package com.best.oasis.settlement.loginservice;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.AuthenticationServiceException;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.providers.AuthenticationProvider;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.providers.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.providers.dao.SaltSource;
import org.springframework.security.providers.encoding.PasswordEncoder;
import org.springframework.security.providers.encoding.PlaintextPasswordEncoder;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.util.Assert;

import com.best.oasis.settlement.util.LDAPUtil;

/**
 * An {@link AuthenticationProvider} implementation that retrieves user details
 * from an {@link UserDetailsService}.
 *
 * @author Ben Alex
 * @version $Id: DaoAuthenticationProvider.java 2653 2008-02-18 20:18:40Z luke_t $
 */
public class MyLdapAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
	/**
	 * Logger for this class
	 */
	private static final Log logger = LogFactory.getLog(MyLdapAuthenticationProvider.class);

	    //~ Instance fields ================================================================================================

	    private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();

	    private SaltSource saltSource;

	    private UserDetailsService userDetailsService;

	    private boolean includeDetailsObject = true;

	    //~ Methods ========================================================================================================

	    
	    
	    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
	    	Authentication result = super.authenticate(authentication);
	    	logger.info("user " + authentication.getName() + " loginned through LDAP.");
	    	/*MyLdapUserDetailsImpl principal = new MyLdapUserDetailsImpl();
	    	UserDetails details = (UserDetails)result.getPrincipal();
	    	principal.setUsername(details.getUsername());
	    	principal.setPassword(details.getPassword());*/
	    	return result;
	    }
	    
	    protected void additionalAuthenticationChecks(UserDetails userDetails,
	            UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
			Object salt = null;

	        if (this.saltSource != null) {
	            salt = this.saltSource.getSalt(userDetails);
	        }

	        if (authentication.getCredentials() == null) {
	            throw new BadCredentialsException(messages.getMessage(
	                    "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
	                    includeDetailsObject ? userDetails : null);
	        }

	        String presentedPassword = authentication.getCredentials().toString();
	        
	        //这里使用LDAP验证
	        if (!LDAPUtil.validateByLdap(userDetails.getUsername(), presentedPassword)) {
	            throw new BadCredentialsException(messages.getMessage(
	                    "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
	                    includeDetailsObject ? userDetails : null);
	        }
	    }

	    protected void doAfterPropertiesSet() throws Exception {
	        Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
	    }

	    protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
	            throws AuthenticationException {
	        UserDetails loadedUser;

	        try {
	            loadedUser = this.getUserDetailsService().loadUserByUsername(username);
	        }
	        catch (DataAccessException repositoryProblem) {
	            throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
	        }

	        if (loadedUser == null) {
	            throw new AuthenticationServiceException(
	                    "UserDetailsService returned null, which is an interface contract violation");
	        }
	        return loadedUser;
	    }

	    /**
	     * Sets the PasswordEncoder instance to be used to encode and validate passwords.
	     * If not set, {@link PlaintextPasswordEncoder} will be used by default.
	     *
	     * @param passwordEncoder The passwordEncoder to use
	     */
	    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
	        this.passwordEncoder = passwordEncoder;
	    }

	    protected PasswordEncoder getPasswordEncoder() {
	        return passwordEncoder;
	    }

	    /**
	     * The source of salts to use when decoding passwords. <code>null</code>
	     * is a valid value, meaning the <code>DaoAuthenticationProvider</code>
	     * will present <code>null</code> to the relevant <code>PasswordEncoder</code>.
	     *
	     * @param saltSource to use when attempting to decode passwords via the <code>PasswordEncoder</code>
	     */
	    public void setSaltSource(SaltSource saltSource) {
	        this.saltSource = saltSource;
	    }

	    protected SaltSource getSaltSource() {
	        return saltSource;
	    }

	    public void setUserDetailsService(UserDetailsService userDetailsService) {
	        this.userDetailsService = userDetailsService;
	    }

	    protected UserDetailsService getUserDetailsService() {
	        return userDetailsService;
	    }

	    protected boolean isIncludeDetailsObject() {
	        return includeDetailsObject;
	    }

	    /**
	     * Determines whether the UserDetails will be included in the <tt>extraInformation</tt> field of a
	     * thrown BadCredentialsException. Defaults to true, but can be set to false if the exception will be
	     * used with a remoting protocol, for example.
	     *
	     * @deprecated use {@link org.springframework.security.providers.ProviderManager#setClearExtraInformation(boolean)}
	     */
	    public void setIncludeDetailsObject(boolean includeDetailsObject) {
	        this.includeDetailsObject = includeDetailsObject;
		}


}
